home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
lisp
/
kcl
/
kcl.lha
/
c
/
alloc.c
next >
Wrap
C/C++ Source or Header
|
1987-06-04
|
18KB
|
903 lines
/*
(c) Copyright Taiichi Yuasa and Masami Hagiya, 1984. All rights reserved.
Copying of this file is authorized to users who have executed the true and
proper "License Agreement for Kyoto Common LISP" with SIGLISP.
*/
/*
alloc.c
IMPLEMENTATION-DEPENDENT
*/
#include "include.h"
object Vignore_maximum_pages;
#ifdef AV
#ifdef ATT3B2
#define page(p) (((int)(char *)(p)-0x80800000)>>PAGEWIDTH)
#define pagetochar(x) ((char *)(((x) << PAGEWIDTH) + 0x80800000))
#else
#define page(p) ((int)(char *)(p)>>PAGEWIDTH)
#define pagetochar(x) ((char *)((x) << PAGEWIDTH))
#endif
#endif
#ifdef MV
#endif
int real_maxpage = MAXPAGE;
int new_holepage;
#define available_pages \
(real_maxpage-page(heap_end)-new_holepage-2*nrbpage-real_maxpage/32)
#ifdef UNIX
extern char *sbrk();
#endif
#ifdef BSD
#include <sys/time.h>
#include <sys/resource.h>
struct rlimit data_rlimit;
extern etext;
#endif
char *
alloc_page(n)
int n;
{
char *e;
int m;
#ifdef AOSVS
#endif
e = heap_end;
if (n >= 0) {
if (n >= holepage) {
holepage = new_holepage + n;
GBC(t_relocatable);
}
holepage -= n;
heap_end += PAGESIZE*n;
return(e);
}
n = -n;
m = (core_end - heap_end)/PAGESIZE;
if (n <= m)
return(e);
#ifdef BSD
if (core_end != sbrk(0))
error("Someone allocated my memory!");
if (core_end != sbrk(PAGESIZE*(n - m)))
error("Can't allocate. Good-bye!");
#endif
#ifdef ATT
if (PAGESIZE*(n - m) > pagetochar(MAXPAGE) - core_end)
error("Can't allocate. Good-bye!");
#endif
#ifdef E15
if (PAGESIZE*(n - m) > pagetochar(MAXPAGE) - core_end)
error("Can't allocate. Good-bye!");
#endif
#ifdef DGUX
#endif
#ifdef AOSVS
#endif
core_end += PAGESIZE*(n - m);
#ifdef AOSVS
#endif
return(e);
}
object
alloc_object(t)
enum type t;
{
STATIC object obj;
STATIC struct typemanager *tm;
STATIC int i;
STATIC char *p;
STATIC object x, f;
ONCE_MORE:
tm = tm_of(t);
if (interrupt_flag) {
interrupt_flag = FALSE;
#ifdef UNIX
alarm(0);
#endif
terminal_interrupt(TRUE);
goto ONCE_MORE;
}
obj = tm->tm_free;
if (obj == OBJNULL) {
if (tm->tm_npage >= tm->tm_maxpage)
goto CALL_GBC;
if (available_pages < 1) {
Vignore_maximum_pages->s.s_dbind = Cnil;
goto CALL_GBC;
}
p = alloc_page(1);
type_map[page(p)] = (char)tm->tm_type;
f = tm->tm_free;
for (i = tm->tm_nppage; i > 0; --i, p += tm->tm_size) {
x = (object)p;
((struct freelist *)x)->t = (short)tm->tm_type;
((struct freelist *)x)->m = FREE;
((struct freelist *)x)->f_link = f;
f = x;
}
obj = tm->tm_free = f;
tm->tm_nfree += tm->tm_nppage;
tm->tm_npage++;
if (tm->tm_npage >= tm->tm_maxpage)
goto CALL_GBC;
}
tm->tm_free = ((struct freelist *)obj)->f_link;
--(tm->tm_nfree);
(tm->tm_nused)++;
obj->d.t = (short)t;
obj->d.m = FALSE;
return(obj);
CALL_GBC:
GBC(tm->tm_type);
if (tm->tm_nfree == 0 ||
(float)tm->tm_nfree * 10.0 < (float)tm->tm_nused)
goto EXHAUSTED;
goto ONCE_MORE;
EXHAUSTED:
if (symbol_value(Vignore_maximum_pages) != Cnil) {
if (tm->tm_maxpage/2 <= 0)
tm->tm_maxpage += 1;
else
tm->tm_maxpage += tm->tm_maxpage/2;
goto ONCE_MORE;
}
GBC_enable = FALSE;
vs_push(make_simple_string(tm_table[(int)t].tm_name+1));
vs_push(make_fixnum(tm->tm_npage));
GBC_enable = TRUE;
CEerror("The storage for ~A is exhausted.~%\
Currently, ~D pages are allocated.~%\
Use ALLOCATE to expand the space.",
"Continues execution.",
2, vs_top[-2], vs_top[-1]);
vs_pop;
vs_pop;
goto ONCE_MORE;
}
object
make_cons(a, d)
object a, d;
{
STATIC object obj;
STATIC int i;
STATIC char *p;
STATIC object x, f;
#define tm (&tm_table[(int)t_cons])
ONCE_MORE:
if (interrupt_flag) {
interrupt_flag = FALSE;
#ifdef UNIX
alarm(0);
#endif
terminal_interrupt(TRUE);
goto ONCE_MORE;
}
obj = tm->tm_free;
if (obj == OBJNULL) {
if (tm->tm_npage >= tm->tm_maxpage)
goto CALL_GBC;
if (available_pages < 1) {
Vignore_maximum_pages->s.s_dbind = Cnil;
goto CALL_GBC;
}
p = alloc_page(1);
type_map[page(p)] = (char)t_cons;
f = tm->tm_free;
for (i = tm->tm_nppage; i > 0; --i, p += tm->tm_size) {
x = (object)p;
((struct freelist *)x)->t = (short)t_cons;
((struct freelist *)x)->m = FREE;
((struct freelist *)x)->f_link = f;
f = x;
}
obj = tm->tm_free = f;
tm->tm_nfree += tm->tm_nppage;
tm->tm_npage++;
if (tm->tm_npage >= tm->tm_maxpage)
goto CALL_GBC;
}
tm->tm_free = ((struct freelist *)obj)->f_link;
--(tm->tm_nfree);
(tm->tm_nused)++;
obj->c.t = (short)t_cons;
obj->c.m = FALSE;
obj->c.c_car = a;
obj->c.c_cdr = d;
return(obj);
CALL_GBC:
GBC(t_cons);
if (tm->tm_nfree == 0 ||
(float)tm->tm_nfree * 10.0 < (float)tm->tm_nused)
goto EXHAUSTED;
goto ONCE_MORE;
EXHAUSTED:
if (symbol_value(Vignore_maximum_pages) != Cnil) {
if (tm->tm_maxpage/2 <= 0)
tm->tm_maxpage += 1;
else
tm->tm_maxpage += tm->tm_maxpage/2;
goto ONCE_MORE;
}
GBC_enable = FALSE;
vs_push(make_fixnum(tm->tm_npage));
GBC_enable = TRUE;
CEerror("The storage for CONS is exhausted.~%\
Currently, ~D pages are allocated.~%\
Use ALLOCATE to expand the space.",
"Continues execution.",
1, vs_top[-1]);
vs_pop;
goto ONCE_MORE;
#undef tm
}
#define round_up(n) (((n) + 03) & ~03)
char *
alloc_contblock(n)
int n;
{
STATIC char *p;
STATIC struct contblock **cbpp;
STATIC int i;
STATIC int m;
STATIC bool g;
bool gg;
/*
printf("allocating %d-byte contiguous block...\n", n);
*/
g = FALSE;
n = round_up(n);
ONCE_MORE:
if (interrupt_flag) {
interrupt_flag = FALSE;
gg = g;
terminal_interrupt(TRUE);
g = gg;
goto ONCE_MORE;
}
for(cbpp= &cb_pointer; (*cbpp)!=NULL; cbpp= &(*cbpp)->cb_link)
if ((*cbpp)->cb_size >= n) {
p = (char *)(*cbpp);
i = (*cbpp)->cb_size - n;
*cbpp = (*cbpp)->cb_link;
--ncb;
insert_contblock(p+n, i);
return(p);
}
m = (n + PAGESIZE - 1)/PAGESIZE;
if (ncbpage + m > maxcbpage || available_pages < m) {
if (available_pages < m)
Vignore_maximum_pages->s.s_dbind = Cnil;
if (!g) {
GBC(t_contiguous);
g = TRUE;
goto ONCE_MORE;
}
if (symbol_value(Vignore_maximum_pages) != Cnil) {
if (maxcbpage/2 <= 0)
maxcbpage += 1;
else
maxcbpage += maxcbpage/2;
g = FALSE;
goto ONCE_MORE;
}
vs_push(make_fixnum(ncbpage));
CEerror("Contiguous blocks exhausted.~%\
Currently, ~D pages are allocated.~%\
Use ALLOCATE-CONTIGUOUS-PAGES to expand the space.",
"Continues execution.", 1, vs_head);
vs_pop;
g = FALSE;
goto ONCE_MORE;
}
p = alloc_page(m);
for (i = 0; i < m; i++)
type_map[page(p) + i] = (char)t_contiguous;
ncbpage += m;
insert_contblock(p+n, PAGESIZE*m - n);
return(p);
}
insert_contblock(p, s)
char *p;
int s;
{
struct contblock **cbpp, *cbp;
if (s < CBMINSIZE)
return;
ncb++;
cbp = (struct contblock *)p;
cbp->cb_size = s;
for (cbpp = &cb_pointer; *cbpp; cbpp = &((*cbpp)->cb_link))
if ((*cbpp)->cb_size >= s) {
cbp->cb_link = *cbpp;
*cbpp = cbp;
return;
}
cbp->cb_link = NULL;
*cbpp = cbp;
}
char *
alloc_relblock(n)
int n;
{
STATIC char *p;
STATIC bool g;
bool gg;
int i;
/*
printf("allocating %d-byte relocatable block...\n", n);
*/
g = FALSE;
n = round_up(n);
ONCE_MORE:
if (interrupt_flag) {
interrupt_flag = FALSE;
gg = g;
terminal_interrupt(TRUE);
g = gg;
goto ONCE_MORE;
}
if (rb_limit - rb_pointer < n) {
if (!g) {
GBC(t_relocatable);
g = TRUE;
if ((float)(rb_limit - rb_pointer) * 10.0 <
(float)(rb_limit - rb_start))
;
else
goto ONCE_MORE;
}
if (symbol_value(Vignore_maximum_pages) != Cnil) {
if (nrbpage/2 <= 0)
i = 1;
else
i = nrbpage/2;
nrbpage += i;
if (available_pages < 0)
nrbpage -= i;
else {
rb_end = rb_start + PAGESIZE*nrbpage;
rb_limit = rb_end - 2*RB_GETA;
alloc_page(-(holepage + nrbpage));
g = FALSE;
goto ONCE_MORE;
}
}
if (rb_limit > rb_end - 2*RB_GETA)
error("relocatable blocks exhausted");
rb_limit += RB_GETA;
vs_push(make_fixnum(nrbpage));
CEerror("Relocatable blocks exhausted.~%\
Currently, ~D pages are allocated.~%\
Use ALLOCATE-RELOCATABLE-PAGES to expand the space.",
"Continues execution.", 1, vs_head);
vs_pop;
g = FALSE;
goto ONCE_MORE;
}
p = rb_pointer;
rb_pointer += n;
return(p);
}
init_tm(t, name, elsize, maxpage)
enum type t;
char name[];
int elsize, maxpage;
{
int i, j;
tm_table[(int)t].tm_name = name;
for (j = -1, i = 0; i < (int)t_end; i++)
if (tm_table[i].tm_size != 0 &&
tm_table[i].tm_size >= elsize &&
(j < 0 || tm_table[j].tm_size > tm_table[i].tm_size))
j = i;
if (j >= 0) {
tm_table[(int)t].tm_type = (enum type)j;
tm_table[j].tm_maxpage += maxpage;
return;
}
tm_table[(int)t].tm_type = t;
tm_table[(int)t].tm_size = round_up(elsize);
tm_table[(int)t].tm_nppage = PAGESIZE/round_up(elsize);
tm_table[(int)t].tm_free = OBJNULL;
tm_table[(int)t].tm_nfree = 0;
tm_table[(int)t].tm_nused = 0;
tm_table[(int)t].tm_npage = 0;
tm_table[(int)t].tm_maxpage = maxpage;
tm_table[(int)t].tm_gbccount = 0;
}
set_maxpage()
{
#ifdef BSD
getrlimit(RLIMIT_DATA, &data_rlimit);
real_maxpage = ((int)&etext + data_rlimit.rlim_cur)/PAGESIZE;
if (real_maxpage > MAXPAGE)
real_maxpage = MAXPAGE;
#endif
#ifdef ATT
real_maxpage = MAXPAGE;
#endif
#ifdef E15
real_maxpage = MAXPAGE;
#endif
#ifdef DGUX
#endif
#ifdef AOSVS
#endif
}
init_alloc()
{
int i, j;
struct typemanager *tm;
char *p, *q;
enum type t;
int c;
#ifdef AOSVS
#endif
holepage = INIT_HOLEPAGE;
new_holepage = HOLEPAGE;
nrbpage = INIT_NRBPAGE;
set_maxpage();
#ifdef UNIX
heap_end = sbrk(0);
if (i = ((int)heap_end & (PAGESIZE - 1)))
sbrk(PAGESIZE - i);
heap_end = core_end = sbrk(0);
#endif
#ifdef ATT
if (brk(pagetochar(MAXPAGE)) < 0)
error("Can't allocate. Good-bye!.");
#endif
#ifdef E15
if (brk(pagetochar(MAXPAGE)) < 0)
error("Can't allocate. Good-bye!.");
#endif
#ifdef AOSVS
#endif
alloc_page(-(holepage + nrbpage));
rb_start = rb_pointer = heap_end + PAGESIZE*holepage;
rb_end = rb_start + PAGESIZE*nrbpage;
rb_limit = rb_end - 2*RB_GETA;
for (i = 0; i < MAXPAGE; i++)
type_map[i] = (char)t_other;
init_tm(t_fixnum, "Nfixnum",
sizeof(struct fixnum_struct), 32);
init_tm(t_cons, ".cons", sizeof(struct cons), 384);
init_tm(t_structure, "Sstructure", sizeof(struct structure), 32);
init_tm(t_string, "\"string", sizeof(struct string), 64);
init_tm(t_array, "aarray", sizeof(struct array), 64);
init_tm(t_symbol, "|symbol", sizeof(struct symbol), 64);
init_tm(t_bignum, "Bbignum", sizeof(struct bignum), 16);
init_tm(t_ratio, "Rratio", sizeof(struct ratio), 1);
init_tm(t_shortfloat, "Fshort-float",
sizeof(struct shortfloat_struct), 1);
init_tm(t_longfloat, "Llong-float",
sizeof(struct longfloat_struct), 1);
init_tm(t_complex, "Ccomplex", sizeof(struct complex), 1);
init_tm(t_character,"#character",sizeof(struct character),1);
init_tm(t_package, ":package", sizeof(struct package), 1);
init_tm(t_hashtable, "hhash-table", sizeof(struct hashtable), 1);
init_tm(t_vector, "vvector", sizeof(struct vector), 2);
init_tm(t_bitvector, "bbit-vector", sizeof(struct bitvector), 1);
init_tm(t_stream, "sstream", sizeof(struct stream), 1);
init_tm(t_random, "$random-state", sizeof(struct random), 1);
init_tm(t_readtable, "rreadtable", sizeof(struct readtable), 1);
init_tm(t_pathname, "ppathname", sizeof(struct pathname), 1);
init_tm(t_cfun, "fcfun", sizeof(struct cfun), 32);
init_tm(t_cclosure, "ccclosure", sizeof(struct cclosure), 1);
init_tm(t_spice, "!spice", sizeof(struct spice), 16);
ncb = 0;
ncbpage = 0;
maxcbpage = 512;
}
cant_get_a_type()
{
FEerror("Can't get a type.", 0);
}
siLalloc()
{
struct typemanager *tm;
int c, i;
char *p, *pp;
object f, x;
if (vs_top - vs_base < 2)
too_few_arguments();
if (vs_top - vs_base > 3)
too_many_arguments();
vs_base[0] = coerce_to_string(vs_base[0]);
if (type_of(vs_base[1]) != t_fixnum ||
(i = fix(vs_base[1])) < 0)
FEerror("~A is not a non-negative fixnum.", 1, vs_base[1]);
if (vs_base[0]->st.st_fillp == 0)
cant_get_a_type();
c = vs_base[0]->st.st_self[0];
for (tm = &tm_table[(int)t_start];
tm < &tm_table[(int)t_end];
tm++)
if (c == tm->tm_name[0]) {
tm = &tm_table[(int)tm->tm_type];
if (tm->tm_npage > i) {
vs_push(make_simple_string(tm->tm_name+1));
vs_push(make_fixnum(tm->tm_npage));
FEerror("Can't set the limit for ~A to ~D pages,~%\
since ~D pages are already allocated.", 3, vs_top[-2],vs_base[1],vs_top[-1]);
}
tm->tm_maxpage = i;
if (vs_top - vs_base == 3 && vs_base[2] != Cnil &&
tm->tm_maxpage > tm->tm_npage)
goto ALLOCATE;
vs_top = vs_base;
vs_push(Ct);
return;
}
cant_get_a_type();
ALLOCATE:
if (available_pages < tm->tm_maxpage - tm->tm_npage ||
(pp = alloc_page(tm->tm_maxpage - tm->tm_npage)) == NULL) {
vs_push(make_simple_string(tm->tm_name+1));
FEerror("Can't allocate ~D pages for ~A.", 2, vs_base[1], vs_top[-1]);
}
for (; tm->tm_npage < tm->tm_maxpage; pp += PAGESIZE) {
p = pp;
type_map[page(p)] = (char)tm->tm_type;
f = tm->tm_free;
for (i = tm->tm_nppage; i > 0; --i, p += tm->tm_size) {
x = (object)p;
((struct freelist *)x)->t = (short)tm->tm_type;
((struct freelist *)x)->m = FREE;
((struct freelist *)x)->f_link = f;
f = x;
}
tm->tm_free = f;
tm->tm_nfree += tm->tm_nppage;
tm->tm_npage++;
}
vs_top = vs_base;
vs_push(Ct);
}
siLnpage()
{
struct typemanager *tm;
int c;
check_arg(1);
vs_base[0] = coerce_to_string(vs_base[0]);
if (vs_base[0]->st.st_fillp == 0)
cant_get_a_type();
c = vs_base[0]->st.st_self[0];
for (tm = &tm_table[(int)t_start];
tm < &tm_table[(int)t_end];
tm++)
if (c == tm->tm_name[0]) {
tm = &tm_table[(int)tm->tm_type];
vs_base[0] = make_fixnum(tm->tm_npage);
return;
}
cant_get_a_type();
}
siLmaxpage()
{
struct typemanager *tm;
int c;
check_arg(1);
vs_base[0] = coerce_to_string(vs_base[0]);
if (vs_base[0]->st.st_fillp == 0)
cant_get_a_type();
c = vs_base[0]->st.st_self[0];
for (tm = &tm_table[(int)t_start];
tm < &tm_table[(int)t_end];
tm++)
if (c == tm->tm_name[0]) {
tm = &tm_table[(int)tm->tm_type];
vs_base[0] = make_fixnum(tm->tm_maxpage);
return;
}
cant_get_a_type();
}
siLalloc_contpage()
{
int i, m;
char *p;
if (vs_top - vs_base < 1)
too_few_arguments();
if (vs_top - vs_base > 2)
too_many_arguments();
if (type_of(vs_base[0]) != t_fixnum ||
(i = fix(vs_base[0])) < 0)
FEerror("~A is not a non-negative fixnum.", 1, vs_base[0]);
if (ncbpage > i) {
vs_push(make_fixnum(ncbpage));
FEerror("Can't set the limit for contiguous blocks to ~D,~%\
since ~D pages are already allocated.",
2, vs_base[0], vs_head);
}
maxcbpage = i;
if (vs_top - vs_base < 2 || vs_base[1] == Cnil) {
vs_top = vs_base;
vs_push(Ct);
return;
}
m = maxcbpage - ncbpage;
if (available_pages < m || (p = alloc_page(m)) == NULL)
FEerror("Can't allocate ~D pages for contiguous blocks.",
1, vs_base[0]);
for (i = 0; i < m; i++)
type_map[page(p + PAGESIZE*i)] = (char)t_contiguous;
ncbpage += m;
insert_contblock(p, PAGESIZE*m);
vs_top = vs_base;
vs_push(Ct);
}
siLncbpage()
{
check_arg(0);
vs_push(make_fixnum(ncbpage));
}
siLmaxcbpage()
{
check_arg(0);
vs_push(make_fixnum(maxcbpage));
}
siLalloc_relpage()
{
int i;
char *p;
if (vs_top - vs_base < 1)
too_few_arguments();
if (vs_top - vs_base > 2)
too_many_arguments();
if (type_of(vs_base[0]) != t_fixnum ||
(i = fix(vs_base[0])) < 0)
FEerror("~A is not a non-negative fixnum.", 1, vs_base[0]);
if (nrbpage > i && rb_pointer >= rb_start + PAGESIZE*i - 2*RB_GETA
|| 2*i > real_maxpage-page(heap_end)-new_holepage-real_maxpage/32)
FEerror("Can't set the limit for relocatable blocks to ~D.",
1, vs_base[0]);
nrbpage = i;
rb_end = rb_start + PAGESIZE*i;
rb_limit = rb_end - 2*RB_GETA;
alloc_page(-(holepage + nrbpage));
vs_top = vs_base;
vs_push(Ct);
}
siLnrbpage()
{
check_arg(0);
vs_push(make_fixnum(nrbpage));
}
siLget_hole_size()
{
check_arg(0);
vs_push(make_fixnum(new_holepage));
}
siLset_hole_size()
{
int i;
check_arg(1);
i = fixint(vs_base[0]);
if (i < 1 ||
i > real_maxpage - page(heap_end) - 2*nrbpage - real_maxpage/32)
FEerror("Illegal value for the hole size.", 0);
new_holepage = i;
}
init_alloc_function()
{
make_si_function("ALLOC", siLalloc);
make_si_function("NPAGE", siLnpage);
make_si_function("MAXPAGE", siLmaxpage);
make_si_function("ALLOC-CONTPAGE", siLalloc_contpage);
make_si_function("NCBPAGE", siLncbpage);
make_si_function("MAXCBPAGE", siLmaxcbpage);
make_si_function("ALLOC-RELPAGE", siLalloc_relpage);
make_si_function("NRBPAGE", siLnrbpage);
make_si_function("GET-HOLE-SIZE", siLget_hole_size);
make_si_function("SET-HOLE-SIZE", siLset_hole_size);
Vignore_maximum_pages
= make_special("*IGNORE-MAXIMUM-PAGES*", Ct);
#ifdef UNIX
#ifndef DGUX
{
extern object malloc_list;
malloc_list = Cnil;
enter_mark_origin(&malloc_list);
}
#endif
#endif
}
#ifdef UNIX
#ifndef DGUX
/*
UNIX malloc simulator.
Used by
getwd, popen, etc.
*/
object malloc_list;
char *
malloc(size)
int size;
{
object x;
x = alloc_simple_string(size);
vs_push(x);
x->st.st_self = alloc_contblock(size);
malloc_list = make_cons(x, malloc_list);
vs_pop;
return(x->st.st_self);
}
free(ptr)
char *ptr;
{
object *p;
for (p = &malloc_list; !endp(*p); p = &((*p)->c.c_cdr))
if ((*p)->c.c_car->st.st_self == ptr) {
insert_contblock((*p)->c.c_car->st.st_self,
(*p)->c.c_car->st.st_dim);
(*p)->c.c_car->st.st_self = NULL;
*p = (*p)->c.c_cdr;
return;
}
FEerror("free(3) error.", 0);
}
char *
realloc(ptr, size)
char *ptr;
int size;
{
object x;
int i, j;
for (x = malloc_list; !endp(x); x = x->c.c_cdr)
if (x->c.c_car->st.st_self == ptr) {
x = x->c.c_car;
if (x->st.st_dim >= size) {
x->st.st_fillp = size;
return(ptr);
} else {
j = x->st.st_dim;
x->st.st_self = alloc_contblock(size);
x->st.st_fillp = x->st.st_dim = size;
for (i = 0; i < size; i++)
x->st.st_self[i] = ptr[i];
insert_contblock(ptr, j);
return(x->st.st_self);
}
}
FEerror("realloc(3) error.", 0);
}
char *
calloc(nelem, elsize)
int nelem, elsize;
{
char *ptr;
int i;
ptr = malloc(i = nelem*elsize);
while (--i >= 0)
ptr[i] = 0;
return(ptr);
}
cfree(ptr)
char *ptr;
{
free(ptr);
}
#endif
#endif